package org.dromara.web.job;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.unit.DataUnit;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
import com.aizuda.snailjob.client.model.ExecuteResult;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.common.log.SnailJobLog;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.nft.domain.NftItem;
import org.dromara.nft.enums.NftType;
import org.dromara.nft.mapper.NftItemMapper;
import org.dromara.system.service.ISysConfigService;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author opensnail
 * @date 2024-05-17
 */
@Component
@JobExecutor(name = "nftJobExecutor")
@AllArgsConstructor
public class NftJobExecutor {


    private final NftItemMapper baseMapper;
    static String CBZ_CB = "0";
    static String HDNL_CB = "0";
  /*  static String ZHXJB_YZ = "0";*/

    //武器:弩 弓 枪 斧 杖 球 长 矛 锤 剑
    static String ZHXJB_WQ_YZ = "0";

    //防具：甲 头 鞋 腰带 手套 盾牌 箭袋
    static String ZHXJB_FJ_YZ = "0";

    //首饰：戒指 项链
    static String ZHXJB_SS_YZ = "0";

    public ExecuteResult jobExecute(JobArgs jobArgs) {
         int PAGE_SIZE = 12;
         String NFT_YZ = "0";
         String EMAIL = "";

         CBZ_CB = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft.cbz.cb");
         HDNL_CB = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft.hdnl.cb");

        SnailJobLog.REMOTE.warn("nftJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs));
        long time = System.currentTimeMillis() / 1000;

        String[] split = jobArgs.getArgsStr().split(",");

        NftType type = NftType.getByName(split[0]);
        PAGE_SIZE = Integer.parseInt(split[1]);

        if (split.length == 3){
            EMAIL = split[2];
        }

        if (type == null) {
            throw new RuntimeException("参数错误！");
        }

        JSONArray resData = new JSONArray();
        getListData(1, type, resData, PAGE_SIZE);
        insertData(resData, time, type);

        NFT_YZ = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft." + type.getValue() + ".yz");

        //综合性价比阈值
        //ZHXJB_YZ = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft.zhxjb.yz");

        ZHXJB_WQ_YZ = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft.zhxjb.wq.yz");
        ZHXJB_FJ_YZ = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft.zhxjb.fj.yz");
        ZHXJB_SS_YZ = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("nft.zhxjb.ss.yz");


        //判断是否发送邮件
        sendMail(type, NFT_YZ, EMAIL);


        return ExecuteResult.success("获取成功");
    }

    private void insertData(JSONArray resData, long time, NftType type) {

        HashSet<NftItem> arrayList = new HashSet<>();

        resData.parallelStream().forEach(item -> {
            JSONObject jsonObject = (JSONObject) item;
            String tokenId = jsonObject.getStr("token_id");
            String title = jsonObject.getStr("title");
            String price = jsonObject.getStr("price");
            long id = jsonObject.getLong("id");

            NftItem nftItem = new NftItem();
            nftItem.setId(tokenId);
            nftItem.setNftType(type.getValue());
            nftItem.setTitle(title);
            nftItem.setPrice(new BigDecimal(price));
            nftItem.setData(jsonObject.toJSONString(0));
            nftItem.setItemId(id);
            nftItem.setVersionNum(String.valueOf(time));
            nftItem.setTenantId("000000");

            if (!title.contains("珍宝碎片包")) {
                arrayList.add(nftItem);
            }
        });

        baseMapper.delete(new LambdaUpdateWrapper<NftItem>().eq(NftItem::getNftType, type.getValue()));
        baseMapper.insertBatch(arrayList);
        getAttributeData(type);
        SnailJobLog.REMOTE.warn("爬取完成！ arrayList:{}", arrayList.size());

    }

    //https://api.actpass.com/nft-api/api/nft/attribute_cache_get/SRF/269986123233/zh
    //https://app.actpass.com/nft

    private void getListData(int page, NftType type, JSONArray resData, int PAGE_SIZE) {


        int allCount = 0;

        String getSigns = "";
        String searchUrl = "https://api.actpass.com/nft-api/api/nft/search";
        String signSecret = "actpass@2022";
        // 1716180360923 / 1e3
        long time = System.currentTimeMillis() / 1000;
        JSONObject body = new JSONObject(true);
        body.put("filter", "");
        body.put("page", page);
        body.put("page_size", PAGE_SIZE);
        body.put("sort", 1);
        body.put("symbol", "");
        body.put("time", time);
        body.put("title", type.getName());

        for (String k : body.keySet()) {
            getSigns += k + body.getStr(k);
        }
        // filterpage1page_size12sort1symboltime1716179737title
        body.put("sign", DigestUtil.md5Hex(getSigns + signSecret));
        SnailJobLog.REMOTE.warn("开始获取. page:{}", page);

        JSONObject parse = null;
        long begin = System.currentTimeMillis();
        HttpResponse execute = null;
        try {
            execute = HttpRequest.post(searchUrl)
                .header("X-Language", "zh")
                .header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0")
                .body(JSONUtil.toJsonStr(body))
                .execute();
            //随机数1-10
            Thread.sleep(1000 + new Random().nextInt(10) * 100);
            parse = JSONUtil.parseObj(execute.body());
            long end = System.currentTimeMillis();
            SnailJobLog.REMOTE.warn("耗时. time:{}", end - begin);

            if (page < 2000 && parse.getInt("code") == 0 && parse != null) {
                JSONObject data = parse.getJSONObject("data");
                allCount = data.getInt("count");
                JSONArray list = data.getJSONArray("list");
                if (list.isEmpty()) {
                    SnailJobLog.REMOTE.error("获取数据为空！");
                    return;
                }
                resData.addAll(list);
                page = page + 1;
                SnailJobLog.REMOTE.warn("获取成功！ 完成百分比 {}/{}, , 本次获取:{}",  resData.size() ,  allCount, list.size());
                getListData(page, type, resData, PAGE_SIZE);

            } else {
                SnailJobLog.REMOTE.error("获取数据为空！body:{}  parse:{}", JSONUtil.toJsonStr(body), parse);
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            SnailJobLog.REMOTE.error("发生错误. err:{}", e.getMessage());
            SnailJobLog.REMOTE.error("发生错误. body:{}", execute.body());
        }
        SnailJobLog.REMOTE.warn("获取完成！ resDataSize:{}", resData.size());
    }


    @SneakyThrows
    public void getAttributeData(NftType type) {
        ForkJoinPool pool = new ForkJoinPool(20);

        AtomicInteger count = new AtomicInteger();
        List<NftItem> finalNftItems = baseMapper.selectList(new LambdaQueryWrapper<NftItem>().eq(NftItem::getNftType, type.getValue()));
        SnailJobLog.REMOTE.warn("开始获取. nftItems:{}, type:{}", finalNftItems.size(), type.getName());

        ForkJoinTask<?> future = pool.submit(() -> {
            finalNftItems.parallelStream().forEach(n -> {
                JSONObject dataJson = JSONUtil.parseObj(n.getData());

                if (!dataJson.isEmpty()) {
                    try {
                        long begin = System.currentTimeMillis();
                        // https://download.seraph.game/chaos_tips/20240512/10207_126455060235_%s.json
                        //String attributeUrl = dataJson.getStr("attribute_url").replace("%s.json", "zh.json");

                        //https://api.actpass.com/nft-api/api/nft/attribute_cache_get/SRF/126700623189/zh
                        //https://api.actpass.com/nft-api/api/nft/attribute_cache_get/MIS/279431774929/zh

                        String attributeUrl = String.format("https://api.actpass.com/nft-api/api/nft/attribute_cache_get/%s/%s/zh",
                            StringUtils.equals(n.getNftType(), NftType.珍宝.getValue()) ? "SRF" : "MIS",
                            n.getId());
                        String redData = HttpUtil.get(attributeUrl);


                        n.setAttribute(redData);
                        long end = System.currentTimeMillis();
                        count.getAndIncrement();

                        BeanUtil.copyProperties(updateAttribute(n), n);

                        SnailJobLog.REMOTE.warn("完成百分比: {}/{}, 耗时. time:{}", count.get(), finalNftItems.size(), end - begin);
                    } catch (Exception e) {
                        SnailJobLog.REMOTE.error("发生错误. err:{}", e.getMessage());
                    }
                }
            });
        });

        future.get();
        SnailJobLog.REMOTE.warn("获取详情成功！");
        pool.shutdown();
    }

    private void sendMail(NftType type,String NFT_YZ, String EMAIL) {
        List<NftItem> mailData = baseMapper.selectList(new LambdaQueryWrapper<NftItem>()
                .select(NftItem::getDwcbz,NftItem::getTitle,NftItem::getItemId,NftItem::getGetAttributeTime,NftItem::getZhxjb)
                .eq(NftItem::getNftType, type.getValue()));
        String mailText = "";

        for (NftItem n : mailData){
            String title =  n.getTitle();
            String yz = NFT_YZ;

            if (n.getDwcbz()!=null && NumberUtil.isLessOrEqual(new BigDecimal(n.getDwcbz().toString()), new BigDecimal(yz))){
                mailText = setMailText(n, mailText, title, yz, "单位财富成本");
                //SnailJobLog.REMOTE.warn("单位财富成本邮件参数！NFT_YZ:{}, mailText:{}, EMAIL:{}",yz,  mailText, EMAIL);
            }
        }

        for (NftItem n : mailData){
            String title =  n.getTitle();

            String[] wq = {"弩", "弓", "枪", "斧", "杖", "球", "长", "矛", "锤", "剑"};
            for (String w : wq) {
                String yz = ZHXJB_WQ_YZ;
                if (title.contains(w)) {
                    if (n.getZhxjb()!=null && NumberUtil.isGreaterOrEqual(new BigDecimal(n.getZhxjb().toString()), new BigDecimal(yz))){
                        mailText = setMailText(n, mailText, title, yz, w + "-武器综合性价比");
                        //SnailJobLog.REMOTE.warn(w + "武器综合性价比邮件参数！ ZHXJB_WQ_YZ:{}, mailText:{}, EMAIL:{}", yz,  mailText, EMAIL);
                    }
                    break;
                }
            }

            String[] fj = {"甲", "头", "鞋", "腰带", "手套", "盾牌", "箭袋"};
            for (String w : fj) {
                String yz = ZHXJB_FJ_YZ;
                if (title.contains(w)) {
//                    if (n.getTitle().contains("126700623189")){
//                        continue;
//                    }


                    if (n.getZhxjb()!=null && NumberUtil.isGreaterOrEqual(new BigDecimal(n.getZhxjb().toString()), new BigDecimal(yz))){
                        mailText = setMailText(n, mailText, title, yz, w + "-防具综合性价比");
                        //SnailJobLog.REMOTE.warn(w + "防具综合性价比邮件参数！ ZHXJB_FJ_YZ:{}, mailText:{}, EMAIL:{}", yz,  mailText, EMAIL);
                    }
                    break;
                }
            }

            String[] ss = {"戒指", "项链"};
            for (String w : ss) {
                String yz = ZHXJB_SS_YZ;
                if (title.contains(w)) {
                    if (n.getZhxjb()!=null && NumberUtil.isGreaterOrEqual(new BigDecimal(n.getZhxjb().toString()), new BigDecimal(yz))){
                        mailText = setMailText(n, mailText, title, yz, w + "-武器综合性价比");
                        //SnailJobLog.REMOTE.warn(w + "首饰综合性价比邮件参数！ ZHXJB_SS_YZ:{}, mailText:{}, EMAIL:{}", yz,  mailText, EMAIL);
                    }
                    break;
                }
            }

        }


        if (StringUtils.isNotEmpty(mailText) && StringUtils.isNotEmpty(EMAIL)){
            MailUtils.sendHtml(EMAIL,"Nft提醒"+ type.getName(), mailText);
            SnailJobLog.REMOTE.warn("邮件发送成功！");
        }
    }

    @NotNull
    private static String setMailText(NftItem n, String mailText, String title, String yz, String typeName) {
        mailText += "名称：" + title + "<br>" +
                "链接：https://app.actpass.com/nftDetail?id=" + n.getItemId() + "<br>" +
                 typeName + "：" + n.getZhxjb() + " > 设置的：" + yz +  "<br>" +
                "数据获取时间：" + DateUtil.format(n.getGetAttributeTime(), "yyyy年MM月dd日 HH时mm分ss秒") + "<br>" +
                "<br><br>";
        return mailText;
    }

    public static void main(String[] args) {
        System.err.println(NumberUtil.isGreaterOrEqual(new BigDecimal("0.060"), new BigDecimal("0.015")));
    }

    private NftItem updateAttribute(NftItem n) {
        NftItem _n = new NftItem();
        _n.setId(n.getId());
        _n.setAttribute(n.getAttribute());
        _n.setGetAttributeTime(new Date());
        try {
            // 装备等级（珍宝）
            String zbdj = getAttributeItem(n.getAttribute(), "物品等级");
            if (StringUtils.isNotEmpty(zbdj)) {
                _n.setZbdj(zbdj);
            }

            if (n.getAttribute().contains("未鉴定")) {
                _n.setJd("未鉴定");

                if (StringUtils.equals(_n.getZbdj(), "30")){
                    _n.setCbz("10");
                    _n.setHdnl("2000");
                }else if (StringUtils.equals(_n.getZbdj(), "40")){
                    _n.setCbz("30");
                    _n.setHdnl("6000");
                }else  if (StringUtils.equals(_n.getZbdj(), "50")){
                    _n.setCbz("100");
                    _n.setHdnl("20000");
                } else {
                    _n.setCbz("0");
                    _n.setHdnl("0");
                }

            } else {
                _n.setJd("已鉴定");
                // 财宝值 （珍宝、混沌余烬、混沌源晶）
                String cbz = getAttributeItem(n.getAttribute(), "财宝值");
                if (StringUtils.isNotEmpty(cbz)) {
                    _n.setCbz(cbz);
                }
            }

            //混沌能量 （珍宝、混沌余烬、混沌源晶）
            String hdnl = getAttributeItem(n.getAttribute(), "混沌能量");
            if (StringUtils.isNotEmpty(hdnl)) {
                _n.setHdnl(hdnl);
            }

            if (StringUtils.equals(n.getNftType(), NftType.珍宝.getValue())) {
                if (StringUtils.isEmpty(_n.getCbz()) || n.getPrice() == null) {
                    throw new RuntimeException("获取失败");
                }
                // 单位财富成本  单位成本=卖价0.1÷财富值10=0.01 （珍宝、混沌余烬、混沌源晶）
                BigDecimal dwcbz = NumberUtil.div(n.getPrice(), new BigDecimal(_n.getCbz()));
                _n.setDwcbz(NumberUtil.round(dwcbz, 6));

//                           String zbdj = getAttributeItem(n.getAttribute(), "物品等级");
//                           if (StringUtils.isNotEmpty(zbdj)) {
//                               _n.setZbdj(zbdj);
//                           }

                //  继承财富 继承财富=财富值×0.8  （珍宝）
                BigDecimal jccfz = NumberUtil.mul(new BigDecimal(_n.getCbz()), new BigDecimal("0.8"));
                _n.setJccfz(NumberUtil.round(jccfz, 6));

                // 继承单位财富成本=售价÷继承财富 （珍宝）
                BigDecimal jccfcb = NumberUtil.div(n.getPrice(), _n.getJccfz());
                _n.setJccfcb(NumberUtil.round(jccfcb, 6));

                //综合性价比 综合性价比=（财宝值×财宝值成本+混沌能量×混沌能量成本）÷售价
                if (StringUtils.isNotEmpty(CBZ_CB) && StringUtils.isNotEmpty(HDNL_CB)){
                    String hdnlCf = _n.getHdnl().split("/")[0];
                    _n.setZhxjb(NumberUtil.div(NumberUtil.add(NumberUtil.mul(_n.getCbz(), CBZ_CB),  NumberUtil.mul(hdnlCf, HDNL_CB)),n.getPrice()));
                }

            } else if (StringUtils.equals(n.getNftType(), NftType.混沌源晶.getValue())) {
                _n.setJd("");
                // 单位财富成本  单位成本=卖价0.1÷混沌能量 （混沌余烬）
                BigDecimal dwcbz = NumberUtil.div(n.getPrice(), new BigDecimal(_n.getHdnl()));
                _n.setDwcbz(NumberUtil.round(dwcbz, 6));

            } else if (StringUtils.equals(n.getNftType(), NftType.混沌余烬.getValue())) {
                _n.setJd("");
                if (StringUtils.isEmpty(_n.getCbz()) || n.getPrice() == null) {
                    throw new RuntimeException("获取失败");
                }
                // 单位财富成本  单位成本=卖价0.1÷财富值10=0.01 （珍宝、混沌余烬）
                BigDecimal dwcbz = NumberUtil.div(n.getPrice(), new BigDecimal(_n.getCbz()));
                _n.setDwcbz(NumberUtil.round(dwcbz, 6));
            }

            baseMapper.updateById(_n);

        } catch (Exception e) {
            SnailJobLog.REMOTE.warn("数据异常！. Attribute:{}", n.getAttribute());
        }

        return _n;
    }


    /**
     * 取出 attributeName 的 attributeValue
     *
     * @param attribute
     * @param attributeName
     */
    private String getAttributeItem(String attribute, String attributeName) {

        JSONArray attributeArr = JSONUtil.parseArray(attribute);
        //取出 attributeName 的 attributeValue 返回
        return attributeArr.stream().filter(attributeItem -> {
            JSONObject jsonObject = (JSONObject) attributeItem;
            return Objects.equals(jsonObject.getStr("attribute_name"), attributeName);
        }).map(attributeItem -> {
            JSONObject jsonObject = (JSONObject) attributeItem;
            return jsonObject.getStr("attribute_value");
        }).findFirst().orElse("");

    }
}
